#ifndef IA32PROCESSORSTATE_H
#define IA32PROCESSORSTATE_H

#include <iostream>
#include "crossbit/ProcessorState.h"
#include "crossbit/SYSCALL.h"

namespace crossbit {

	class IA32ProcessorState : public ProcessorState
	{
		public:
			IA32ProcessorState() {
				p_tls = 6;
				// add by suntingtao 2008-12-13
				fpu_top = (XTMemAddr)(fpu_stack) + 128;

				for( int i = 0 ; i < EOR ; i++ ) r_[i] = 0;

				for( int i = 0 ; i < 36 ; i++ ) fpr_[i] = 0;
			}

			// added by zhangyichao, 2010-4-20
			IA32ProcessorState(const IA32ProcessorState &s_state)
			{
				for(int i = 0; i < EOR; i++)
					this->r_[i] = s_state.r_[i];
				for(int i = 0; i < 36; i++)
					this->fpr_[i] = s_state.fpr_[i];
				for(int i = 0; i < 128; i++)
					this->fpu_stack[i] = s_state.fpu_stack[i];
				this->fpu_top = s_state.fpu_top;
				this->p_tls = s_state.p_tls;
			}

			IA32ProcessorState& operator=(const IA32ProcessorState &s_state)
			{
				for(int i = 0; i < EOR; i++)
					this->r_[i] = s_state.r_[i];
				for(int i = 0; i < 36; i++)
					this->fpr_[i] = s_state.fpr_[i];
				for(int i = 0; i < 128; i++)
					this->fpu_stack[i] = s_state.fpu_stack[i];
				this->fpu_top = s_state.fpu_top;
				this->p_tls = s_state.p_tls;

				return (*this);
			}

			/* total 12 internal registers numbered 0, 1, 2 ..., 11 */
			enum IA32 {
				/* 8 general purpose register */
				EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI, 
				//Segment Register
				ES,CS,SS,DS,FS,GS,

				PC,
				// reserved for lazy evaluation of condition code
				// add by chuchao,we only choose to emulate the six FLAGS below which are in common use.
				CF,OF,SF,ZF,AF,PF,DF,
				//XXX   
				FControl,FStatus,Ftag,

				REG1, SEG_BASE, 
				EOR // end of register
			};

			enum X87 {
				//XXX
				FD0,FD1,FD2,FD3,FD4,FD5,FD6,FD7,
				FEOR
			};

			// add by suntingtao , 2008-12-13
			XTMemAddr getFPUStackTop() {
				return fpu_top;
			}

			void setFPUStackTop( XTMemAddr addr ){
				if( addr < (XTMemAddr)(fpu_stack) || addr > (XTMemAddr)(fpu_stack) + 128) {
					printf("Error in IA32ProcessorState.h : setFPUStackTop\n");
					assert(0);
				} else {
					fpu_top = addr;
				}
			}

			virtual MemAddr get(RegNum reg) const
			{
				return (MemAddr) &r_[reg];
			}

			virtual MemAddr fpget(RegNum reg) const
			{
				return (MemAddr) &fpr_[ 3 * reg];
			}

			XTInt32 reg(RegNum reg) const
			{
				// printf("in ia32: xxxxxxxxxx\n");
				return r_[reg];
			}

			Word fpreg(RegNum reg) const
			{
				return fpr_[3 * reg];
			}

			inline void put(RegNum reg, Word value) 
			{
				r_[reg] = value;
			}

			void fpput(RegNum reg, Word value) 
			{
				fpr_[reg] = value;
			}

			int size() const
			{
				return 8;
			}

			int fpsize() const
			{
				return 12;
			}
			/*
			   int set_tls( struct user_desc *desc )
			   {
			   desc->entry_number = p_tls;
			   memcpy( &tls[p_tls-6], desc, sizeof(struct user_desc) );
			   p_tls++;
			   return 0;
			   }

			   int get_tls( struct user_desc *desc )
			   {
			   memcpy( desc, &tls[desc->entry_number-6], sizeof(struct user_desc) );
			   return 0;
			   }
			   */
			void dump() 
			{
				std::cout << "IA32 Register File Dump: " << std::endl
					<< "\tEAX: 0x" << std::hex << r_[0] << std::endl
					<< "\tECX: 0x" << std::hex << r_[1] << std::endl
					<< "\tEDX: 0x" << std::hex << r_[2] << std::endl
					<< "\tEBX: 0x" << std::hex << r_[3] << std::endl
					<< "\tESP: 0x" << std::hex << r_[4] << std::endl
					<< "\tEBP: 0x" << std::hex << r_[5] << std::endl
					<< "\tESI: 0x" << std::hex << r_[6] << std::endl
					<< "\tEDI: 0x" << std::hex << r_[7] << std::endl

					<< "\tES: 0x" << std::hex << r_[8] << std::endl
					<< "\tCS: 0x" << std::hex << r_[9] << std::endl
					<< "\tSS: 0x" << std::hex << r_[10] << std::endl
					<< "\tDS: 0x" << std::hex << r_[11] << std::endl
					<< "\tFS: 0x" << std::hex << r_[12] << std::endl
					<< "\tGS: 0x" << std::hex << r_[13] << std::endl

					<< "\tCF: " << r_[15]  << std::endl
					<< "\tOF: " << r_[16] << std::endl
					<< "\tSF: " << r_[17] << std::endl
					<< "\tZF: " << r_[18] << std::endl;
				/*
				   for( int i = 0 ; i < 16  ; i++ ){
				   printf("\tfpu[%d] = %x\n" , i / 2 * 2 , fpr_[i]  );
				   }
				   */
				int size = fpsize();
				for (int i = 0; i < size; i++)
				{
					XTInt32 *p = (XTInt32 *)fpget(i);
					printf("$f%d: %08x%08x%08x\t", i, *p, *(p+1), *(p+2));

					if (i % 2 == 1)
						printf("\n");
				}
			}

			void dumpToFile( XTFile fd );

			void loadFromFile( XTFile fd );

		private:
			Word r_[EOR];
			Word fpr_[36];
			// QWord fpr_[FEOR];
			//          struct user_desc tls[3];
			// add by stt , 2008-12-13 , to emulate the FPU data register stack 
			XTUint8 fpu_stack[128];
			// get the top of the fpu_stack at the beginning , the fpu_top = fpu_stack + 128;
			XTMemAddr fpu_top;

			int p_tls;
	};
}

#endif
